#!/usr/bin/env python3
"""
Vision Configuration Manager - 视觉系统配置管理器
管理视觉交互系统的配置参数和验证
"""

import os
import re
import logging
from typing import Dict, Any, Optional, Tuple
from dataclasses import dataclass, field
from pathlib import Path


@dataclass
class VisionConfig:
    """视觉系统配置数据类"""
    # 基本配置
    enabled: bool = True
    processing_timeout: int = 10
    max_image_size: str = "1920x1080"
    jpeg_quality: int = 85
    
    # Coze API配置
    coze_api_key: Optional[str] = None
    coze_bot_id: Optional[str] = None
    
    # 本地模型配置
    local_model_enabled: bool = True
    local_model_path: Optional[str] = None
    fallback_to_local: bool = True
    
    # 摄像头配置
    camera_rtsp_url: str = "rtsp://<CAMERA_IP>:8554/stream"
    camera_http_port: int = 8080
    frame_capture_interval: float = 1.0
    default_resolution: str = "640x480"
    default_fps: int = 15
    supported_formats: list = field(default_factory=lambda: ["JPEG", "RGB565", "YUV422"])
    
    # 处理配置
    batch_processing: bool = False
    gpu_acceleration: bool = True
    model_quantization: bool = True
    cache_results: bool = True
    cache_ttl: int = 300
    
    # WebSocket配置
    vision_query_timeout: int = 30
    max_image_data_size: int = 10485760  # 10MB
    enable_binary_transfer: bool = True


class VisionConfigManager:
    """视觉配置管理器"""
    
    def __init__(self, logger=None):
        self.logger = logger or logging.getLogger(__name__)
        self.config = VisionConfig()
        self._config_file_path = None
        
    def load_from_dict(self, config_dict: Dict[str, Any]) -> bool:
        """从字典加载配置"""
        try:
            vision_config = config_dict.get('vision', {})
            
            if not vision_config:
                self.logger.warn("No vision configuration found in config dict")
                return False
            
            # 基本配置
            self.config.enabled = vision_config.get('enabled', True)
            self.config.processing_timeout = vision_config.get('processing_timeout', 10)
            self.config.max_image_size = vision_config.get('max_image_size', "1920x1080")
            self.config.jpeg_quality = vision_config.get('jpeg_quality', 85)
            
            # Coze API配置
            self.config.coze_api_key = self._resolve_env_var(vision_config.get('coze_api_key'))
            self.config.coze_bot_id = self._resolve_env_var(vision_config.get('coze_bot_id'))
            
            # 本地模型配置
            self.config.local_model_enabled = vision_config.get('local_model_enabled', True)
            self.config.local_model_path = vision_config.get('local_model_path')
            self.config.fallback_to_local = vision_config.get('fallback_to_local', True)
            
            # 摄像头配置
            camera_config = vision_config.get('camera', {})
            self.config.camera_rtsp_url = camera_config.get('rtsp_url', "rtsp://<CAMERA_IP>:8554/stream")
            self.config.camera_http_port = camera_config.get('http_stream_port', 8080)
            self.config.frame_capture_interval = camera_config.get('frame_capture_interval', 1.0)
            self.config.default_resolution = camera_config.get('default_resolution', "640x480")
            self.config.default_fps = camera_config.get('default_fps', 15)
            self.config.supported_formats = camera_config.get('supported_formats', ["JPEG", "RGB565", "YUV422"])
            
            # 处理配置
            processing_config = vision_config.get('processing', {})
            self.config.batch_processing = processing_config.get('batch_processing', False)
            self.config.gpu_acceleration = processing_config.get('gpu_acceleration', True)
            self.config.model_quantization = processing_config.get('model_quantization', True)
            self.config.cache_results = processing_config.get('cache_results', True)
            self.config.cache_ttl = processing_config.get('cache_ttl', 300)
            
            # WebSocket配置
            websocket_config = vision_config.get('websocket', {})
            self.config.vision_query_timeout = websocket_config.get('vision_query_timeout', 30)
            self.config.max_image_data_size = websocket_config.get('max_image_data_size', 10485760)
            self.config.enable_binary_transfer = websocket_config.get('enable_binary_transfer', True)
            
            self.logger.info("Vision configuration loaded successfully")
            return True
            
        except Exception as e:
            self.logger.error(f"Error loading vision configuration: {e}")
            return False
    
    def load_from_toml_file(self, file_path: str) -> bool:
        """从TOML文件加载配置"""
        try:
            import toml
            
            if not os.path.exists(file_path):
                self.logger.error(f"Configuration file not found: {file_path}")
                return False
            
            with open(file_path, 'r', encoding='utf-8') as f:
                config_dict = toml.load(f)
            
            self._config_file_path = file_path
            return self.load_from_dict(config_dict)
            
        except ImportError:
            self.logger.error("toml library not available. Install with: pip install toml")
            return False
        except Exception as e:
            self.logger.error(f"Error loading TOML configuration: {e}")
            return False
    
    def validate_configuration(self) -> Tuple[bool, list]:
        """验证配置的有效性"""
        errors = []
        
        # 验证基本配置
        if not isinstance(self.config.enabled, bool):
            errors.append("vision.enabled must be a boolean")
        
        if not isinstance(self.config.processing_timeout, int) or self.config.processing_timeout <= 0:
            errors.append("vision.processing_timeout must be a positive integer")
        
        # 验证图像尺寸格式
        if not self._validate_resolution(self.config.max_image_size):
            errors.append(f"Invalid max_image_size format: {self.config.max_image_size}")
        
        if not self._validate_resolution(self.config.default_resolution):
            errors.append(f"Invalid default_resolution format: {self.config.default_resolution}")
        
        # 验证JPEG质量
        if not (1 <= self.config.jpeg_quality <= 100):
            errors.append("jpeg_quality must be between 1 and 100")
        
        # 验证Coze API配置
        if self.config.enabled and not self.config.local_model_enabled:
            if not self.config.coze_api_key:
                errors.append("coze_api_key is required when local model is disabled")
            if not self.config.coze_bot_id:
                errors.append("coze_bot_id is required when local model is disabled")
        
        # 验证本地模型路径
        if self.config.local_model_enabled and self.config.local_model_path:
            if not os.path.exists(self.config.local_model_path):
                errors.append(f"Local model path does not exist: {self.config.local_model_path}")
        
        # 验证摄像头配置
        if not self._validate_rtsp_url(self.config.camera_rtsp_url):
            errors.append(f"Invalid RTSP URL format: {self.config.camera_rtsp_url}")
        
        if not (1 <= self.config.camera_http_port <= 65535):
            errors.append("camera_http_port must be between 1 and 65535")
        
        if not (1 <= self.config.default_fps <= 60):
            errors.append("default_fps must be between 1 and 60")
        
        # 验证WebSocket配置
        if not (1 <= self.config.vision_query_timeout <= 300):
            errors.append("vision_query_timeout must be between 1 and 300 seconds")
        
        if not (1024 <= self.config.max_image_data_size <= 100*1024*1024):
            errors.append("max_image_data_size must be between 1KB and 100MB")
        
        is_valid = len(errors) == 0
        
        if is_valid:
            self.logger.info("Vision configuration validation passed")
        else:
            self.logger.error(f"Vision configuration validation failed: {errors}")
        
        return is_valid, errors
    
    def get_coze_config(self) -> Dict[str, str]:
        """获取Coze API配置"""
        return {
            'api_key': self.config.coze_api_key or '',
            'bot_id': self.config.coze_bot_id or ''
        }
    
    def get_camera_config(self) -> Dict[str, Any]:
        """获取摄像头配置"""
        return {
            'rtsp_url': self.config.camera_rtsp_url,
            'http_port': self.config.camera_http_port,
            'frame_interval': self.config.frame_capture_interval,
            'resolution': self.config.default_resolution,
            'fps': self.config.default_fps,
            'formats': self.config.supported_formats
        }
    
    def get_processing_config(self) -> Dict[str, Any]:
        """获取处理配置"""
        return {
            'timeout': self.config.processing_timeout,
            'max_image_size': self.config.max_image_size,
            'jpeg_quality': self.config.jpeg_quality,
            'batch_processing': self.config.batch_processing,
            'gpu_acceleration': self.config.gpu_acceleration,
            'model_quantization': self.config.model_quantization,
            'cache_results': self.config.cache_results,
            'cache_ttl': self.config.cache_ttl
        }
    
    def get_websocket_config(self) -> Dict[str, Any]:
        """获取WebSocket配置"""
        return {
            'query_timeout': self.config.vision_query_timeout,
            'max_image_size': self.config.max_image_data_size,
            'binary_transfer': self.config.enable_binary_transfer
        }
    
    def is_coze_api_available(self) -> bool:
        """检查Coze API是否可用"""
        return bool(self.config.coze_api_key and self.config.coze_bot_id)
    
    def is_local_model_available(self) -> bool:
        """检查本地模型是否可用"""
        if not self.config.local_model_enabled:
            return False
        
        if not self.config.local_model_path:
            return False
        
        return os.path.exists(self.config.local_model_path)
    
    def get_preferred_vision_service(self) -> str:
        """获取首选的视觉服务"""
        if self.is_coze_api_available():
            return 'coze'
        elif self.is_local_model_available():
            return 'local'
        else:
            return 'none'
    
    def _resolve_env_var(self, value: Optional[str]) -> Optional[str]:
        """解析环境变量"""
        if not value:
            return None
        
        # 处理 ${VAR_NAME} 格式的环境变量
        if value.startswith('${') and value.endswith('}'):
            env_var = value[2:-1]
            return os.getenv(env_var)
        
        return value
    
    def _validate_resolution(self, resolution: str) -> bool:
        """验证分辨率格式"""
        pattern = r'^\d+x\d+$'
        return bool(re.match(pattern, resolution))
    
    def _validate_rtsp_url(self, url: str) -> bool:
        """验证RTSP URL格式"""
        pattern = r'^rtsp://[\w\.-]+:\d+/\w+$'
        return bool(re.match(pattern, url))
    
    def to_dict(self) -> Dict[str, Any]:
        """将配置转换为字典"""
        return {
            'vision': {
                'enabled': self.config.enabled,
                'processing_timeout': self.config.processing_timeout,
                'max_image_size': self.config.max_image_size,
                'jpeg_quality': self.config.jpeg_quality,
                'coze_api_key': self.config.coze_api_key,
                'coze_bot_id': self.config.coze_bot_id,
                'local_model_enabled': self.config.local_model_enabled,
                'local_model_path': self.config.local_model_path,
                'fallback_to_local': self.config.fallback_to_local,
                'camera': {
                    'rtsp_url': self.config.camera_rtsp_url,
                    'http_stream_port': self.config.camera_http_port,
                    'frame_capture_interval': self.config.frame_capture_interval,
                    'default_resolution': self.config.default_resolution,
                    'default_fps': self.config.default_fps,
                    'supported_formats': self.config.supported_formats
                },
                'processing': {
                    'batch_processing': self.config.batch_processing,
                    'gpu_acceleration': self.config.gpu_acceleration,
                    'model_quantization': self.config.model_quantization,
                    'cache_results': self.config.cache_results,
                    'cache_ttl': self.config.cache_ttl
                },
                'websocket': {
                    'vision_query_timeout': self.config.vision_query_timeout,
                    'max_image_data_size': self.config.max_image_data_size,
                    'enable_binary_transfer': self.config.enable_binary_transfer
                }
            }
        }


def test_vision_config_manager():
    """测试视觉配置管理器"""
    import tempfile
    import json
    
    # 创建测试配置
    test_config = {
        'vision': {
            'enabled': True,
            'coze_api_key': '${COZE_API_KEY}',
            'coze_bot_id': '${COZE_BOT_ID}',
            'camera': {
                'rtsp_url': 'rtsp://<CAMERA_IP>:8554/stream',
                'default_resolution': '1280x720'
            }
        }
    }
    
    # 测试配置管理器
    manager = VisionConfigManager()
    
    print("Testing Vision Configuration Manager:")
    print("-" * 50)
    
    # 测试从字典加载
    success = manager.load_from_dict(test_config)
    print(f"Load from dict: {'SUCCESS' if success else 'FAILED'}")
    
    # 测试配置验证
    is_valid, errors = manager.validate_configuration()
    print(f"Configuration validation: {'PASSED' if is_valid else 'FAILED'}")
    if errors:
        for error in errors:
            print(f"  - {error}")
    
    # 测试配置获取
    print(f"Coze config: {manager.get_coze_config()}")
    print(f"Camera config: {manager.get_camera_config()}")
    print(f"Preferred service: {manager.get_preferred_vision_service()}")
    
    # 测试配置导出
    config_dict = manager.to_dict()
    print(f"Export to dict: {json.dumps(config_dict, indent=2)}")


if __name__ == '__main__':
    test_vision_config_manager()